import 'dart:async';
import 'dart:math';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:tiktokadult/assets_tool/images.dart';
import 'package:tiktokadult/config/config.dart';
import 'package:tiktokadult/hj_model/splash/domain_source_model.dart';
import 'package:tiktokadult/hj_utils/widget_utils.dart';

import '../../../hj_utils/api_service/vid_service.dart';
import '../../../routers/jump_router.dart';

class HomeTxtMarQuee extends StatefulWidget {
  final double stepOffset;
  //首页读取type=1，暗网读取type=2,发现读取type=4，社区读取type=3,我的界面读取type=0
  final int typeValue;
  final EdgeInsetsGeometry? margin;
  final bool showClose;
  final double? fontSize;
  final double? iconSize;
  final double? height;
  final EdgeInsets? padding;
  final double borderRadius;

  HomeTxtMarQuee({
    this.stepOffset = 1,
    this.typeValue = 0,
    this.margin,
    this.showClose = false,
    this.fontSize,
    this.iconSize,
    this.height,
    this.padding,
    this.borderRadius = 0,
    super.key,
  });

  @override
  State<StatefulWidget> createState() {
    return HomeTxtMarQueeState();
  }
}

class HomeTxtMarQueeState extends State<HomeTxtMarQuee> {
  List<MarqueeModel>? marquees;

  bool isShow = true;

  @override
  void initState() {
    super.initState();
    marquees = Config.allMarquee;
    if (marquees == null) {
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
        _loadData();
      });
    }
  }

  _loadData() async {
    await VidService.fetchAnnounce(widget.typeValue);
    marquees = Config.allMarquee;
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return (marquees != null && marquees!.isNotEmpty && isShow)
        ? Container(
            height: widget.height ?? 36,
            alignment: Alignment.centerLeft,
            margin: widget.margin,
            padding: widget.padding ?? EdgeInsets.only(left: 14, right: 14, top: 8, bottom: 8),
            decoration: BoxDecoration(
              color: Color(0xff22242E),
              borderRadius: BorderRadius.circular(widget.borderRadius),
            ),
            child: Row(
              children: [
                Image.asset(
                  "icon_broadcast.webp".commonImgPath,
                  width: widget.iconSize ?? 20,
                ),
                6.sizeBoxW,
                Expanded(
                  child: InfiniteMarquee(
                    stepOffset: widget.stepOffset,
                    itemBuilder: (BuildContext context, int index) {
                      final _index = index % marquees!.length;
                      final model = marquees![_index];
                      return InkWell(
                        onTap: () => pushToPageByLink(model.url, id: model.id),
                        child: Text(
                          model.content ?? '',
                          style: TextStyle(color: Color(0xff989898), fontSize: widget.fontSize ?? 12, height: 1.4),
                        ),
                      );
                    },
                  ),
                ),
                if (widget.showClose) ...[
                  6.sizeBoxW,
                  GestureDetector(
                    onTap: () => setState(() => isShow = false),
                    child: Icon(Icons.close, size: 18, color: Color(0xffDCDCDC)),
                  )
                ],
              ],
            ),
          )
        : SizedBox();
  }
}

// 无限滚动list
class InfiniteMarquee extends StatefulWidget {
  /// 每次移动步长,默认0.5,越大越快
  final double stepOffset;

  /// 自定义内容
  final IndexedWidgetBuilder itemBuilder;

  InfiniteMarquee({
    this.stepOffset = 0.5,
    required this.itemBuilder,
  });

  @override
  State<InfiniteMarquee> createState() => _InfiniteMarqueeState();
}

class _InfiniteMarqueeState extends State<InfiniteMarquee> {
  // 执行动画的controller
  InfiniteScrollController? _controller;

  // 定时器timer
  Timer? _timer;

  // 定时器时间
  Duration duration = Duration(milliseconds: 30);

  // 手势打断定时器
  bool timerStop = false;

  // 执行位移开始的偏移量
  double _offset = 0.0;

  @override
  void initState() {
    super.initState();
    _controller = InfiniteScrollController(initialScrollOffset: _offset);
    _startScrollTimer();
  }

  /// 开启定时器
  _startScrollTimer() {
    _timer = Timer.periodic(duration, (timer) {
      _autoScroll();
    });
  }

  /// 自动滚动
  _autoScroll() {
    double newOffset = (_controller?.offset ?? 0) + widget.stepOffset;
    if (timerStop == false) {
      _offset = newOffset;
      _controller?.jumpTo(_offset);
    }
  }

  @override
  void dispose() {
    _timer?.cancel();
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    /// 监听滚动
    return InfiniteListView.separated(
      scrollDirection: Axis.horizontal,
      controller: _controller,
      itemBuilder: widget.itemBuilder,
      physics: NeverScrollableScrollPhysics(),
      separatorBuilder: (BuildContext context, int index) => SizedBox(width: Get.width - 100),
      anchor: 0,
    );
  }
}

class InfiniteListView extends StatefulWidget {
  /// See [ListView.builder]
  const InfiniteListView.builder({
    Key? key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.physics,
    this.padding,
    this.itemExtent,
    required this.itemBuilder,
    this.itemCount,
    this.addAutomaticKeepAlives = true,
    this.addRepaintBoundaries = true,
    this.addSemanticIndexes = true,
    this.cacheExtent,
    this.anchor = 0.0,
    this.dragStartBehavior = DragStartBehavior.start,
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
  })  : separatorBuilder = null,
        super(key: key);

  /// See [ListView.separated]
  const InfiniteListView.separated({
    Key? key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.physics,
    this.padding,
    required this.itemBuilder,
    required this.separatorBuilder,
    this.itemCount,
    this.addAutomaticKeepAlives = true,
    this.addRepaintBoundaries = true,
    this.addSemanticIndexes = true,
    this.cacheExtent,
    this.anchor = 0.0,
    this.dragStartBehavior = DragStartBehavior.start,
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
  })  : itemExtent = null,
        super(key: key);

  /// See: [ScrollView.scrollDirection]
  final Axis scrollDirection;

  /// See: [ScrollView.reverse]
  final bool reverse;

  /// See: [ScrollView.controller]
  final InfiniteScrollController? controller;

  /// See: [ScrollView.physics]
  final ScrollPhysics? physics;

  /// See: [BoxScrollView.padding]
  final EdgeInsets? padding;

  /// See: [ListView.builder]
  final IndexedWidgetBuilder itemBuilder;

  /// See: [ListView.separated]
  final IndexedWidgetBuilder? separatorBuilder;

  /// See: [SliverChildBuilderDelegate.childCount]
  final int? itemCount;

  /// See: [ListView.itemExtent]
  final double? itemExtent;

  /// See: [ScrollView.cacheExtent]
  final double? cacheExtent;

  /// See: [ScrollView.anchor]
  final double anchor;

  /// See: [SliverChildBuilderDelegate.addAutomaticKeepAlives]
  final bool addAutomaticKeepAlives;

  /// See: [SliverChildBuilderDelegate.addRepaintBoundaries]
  final bool addRepaintBoundaries;

  /// See: [SliverChildBuilderDelegate.addSemanticIndexes]
  final bool addSemanticIndexes;

  /// See: [ScrollView.dragStartBehavior]
  final DragStartBehavior dragStartBehavior;

  /// See: [ScrollView.keyboardDismissBehavior]
  final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;

  /// See: [ScrollView.restorationId]
  final String? restorationId;

  /// See: [ScrollView.clipBehavior]
  final Clip clipBehavior;

  @override
  _InfiniteListViewState createState() => _InfiniteListViewState();
}

class _InfiniteListViewState extends State<InfiniteListView> {
  InfiniteScrollController? _controller;

  InfiniteScrollController get _effectiveController => widget.controller ?? _controller!;

  @override
  void initState() {
    super.initState();
    if (widget.controller == null) {
      _controller = InfiniteScrollController();
    }
  }

  @override
  void didUpdateWidget(InfiniteListView oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.controller == null && oldWidget.controller != null) {
      _controller = InfiniteScrollController();
    } else if (widget.controller != null && oldWidget.controller == null) {
      _controller!.dispose();
      _controller = null;
    }
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final List<Widget> slivers = _buildSlivers(context, negative: false);
    final List<Widget> negativeSlivers = _buildSlivers(context, negative: true);
    final AxisDirection axisDirection = _getDirection(context);
    final scrollPhysics = widget.physics ?? const AlwaysScrollableScrollPhysics();
    return Scrollable(
      axisDirection: axisDirection,
      controller: _effectiveController,
      physics: scrollPhysics,
      viewportBuilder: (BuildContext context, ViewportOffset offset) {
        return Builder(builder: (BuildContext context) {
          /// Build negative [ScrollPosition] for the negative scrolling [Viewport].
          final state = Scrollable.of(context);
          final negativeOffset = _InfiniteScrollPosition(
            physics: scrollPhysics,
            context: state,
            initialPixels: -offset.pixels,
            keepScrollOffset: _effectiveController.keepScrollOffset,
            negativeScroll: true,
          );

          /// Keep the negative scrolling [Viewport] positioned to the [ScrollPosition].
          offset.addListener(() {
            negativeOffset._forceNegativePixels(offset.pixels);
          });

          /// Stack the two [Viewport]s on top of each other so they move in sync.
          return Stack(
            children: <Widget>[
              Viewport(
                axisDirection: flipAxisDirection(axisDirection),
                anchor: 1.0 - widget.anchor,
                offset: negativeOffset,
                slivers: negativeSlivers,
                cacheExtent: widget.cacheExtent,
              ),
              Viewport(
                axisDirection: axisDirection,
                anchor: widget.anchor,
                offset: offset,
                slivers: slivers,
                cacheExtent: widget.cacheExtent,
              ),
            ],
          );
        });
      },
    );
  }

  AxisDirection _getDirection(BuildContext context) {
    return getAxisDirectionFromAxisReverseAndDirectionality(context, widget.scrollDirection, widget.reverse);
  }

  List<Widget> _buildSlivers(BuildContext context, {bool negative = false}) {
    final itemExtent = widget.itemExtent;
    final padding = widget.padding ?? EdgeInsets.zero;
    return <Widget>[
      SliverPadding(
        padding: negative ? padding - EdgeInsets.only(bottom: padding.bottom) : padding - EdgeInsets.only(top: padding.top),
        sliver: (itemExtent != null)
            ? SliverFixedExtentList(
                delegate: negative ? negativeChildrenDelegate : positiveChildrenDelegate,
                itemExtent: itemExtent,
              )
            : SliverList(
                delegate: negative ? negativeChildrenDelegate : positiveChildrenDelegate,
              ),
      )
    ];
  }

  SliverChildDelegate get negativeChildrenDelegate {
    return SliverChildBuilderDelegate(
      (BuildContext context, int index) {
        final separatorBuilder = widget.separatorBuilder;
        if (separatorBuilder != null) {
          final itemIndex = (-1 - index) ~/ 2;
          return index.isOdd ? widget.itemBuilder(context, itemIndex) : separatorBuilder(context, itemIndex);
        } else {
          return widget.itemBuilder(context, -1 - index);
        }
      },
      childCount: widget.itemCount,
      addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
      addRepaintBoundaries: widget.addRepaintBoundaries,
    );
  }

  SliverChildDelegate get positiveChildrenDelegate {
    final separatorBuilder = widget.separatorBuilder;
    final itemCount = widget.itemCount;
    return SliverChildBuilderDelegate(
      (separatorBuilder != null)
          ? (BuildContext context, int index) {
              final itemIndex = index ~/ 2;
              return index.isEven ? widget.itemBuilder(context, itemIndex) : separatorBuilder(context, itemIndex);
            }
          : widget.itemBuilder,
      childCount: separatorBuilder == null ? itemCount : (itemCount != null ? max(0, itemCount * 2 - 1) : null),
      addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
      addRepaintBoundaries: widget.addRepaintBoundaries,
    );
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(EnumProperty<Axis>('scrollDirection', widget.scrollDirection));
    properties.add(FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed', showName: true));
    properties.add(DiagnosticsProperty<ScrollController>('controller', widget.controller, showName: false, defaultValue: null));
    properties.add(DiagnosticsProperty<ScrollPhysics>('physics', widget.physics, showName: false, defaultValue: null));
    properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', widget.padding, defaultValue: null));
    properties.add(DoubleProperty('itemExtent', widget.itemExtent, defaultValue: null));
    properties.add(DoubleProperty('cacheExtent', widget.cacheExtent, defaultValue: null));
  }
}

/// Same as a [ScrollController] except it provides [ScrollPosition] objects with infinite bounds.
class InfiniteScrollController extends ScrollController {
  /// Creates a new [InfiniteScrollController]
  InfiniteScrollController({
    double initialScrollOffset = 0.0,
    bool keepScrollOffset = true,
    String? debugLabel,
  }) : super(
          initialScrollOffset: initialScrollOffset,
          keepScrollOffset: keepScrollOffset,
          debugLabel: debugLabel,
        );

  @override
  ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition? oldPosition) {
    return _InfiniteScrollPosition(
      physics: physics,
      context: context,
      initialPixels: initialScrollOffset,
      keepScrollOffset: keepScrollOffset,
      oldPosition: oldPosition,
      debugLabel: debugLabel,
    );
  }
}

class _InfiniteScrollPosition extends ScrollPositionWithSingleContext {
  _InfiniteScrollPosition({
    required ScrollPhysics physics,
    required ScrollContext context,
    double? initialPixels = 0.0,
    bool keepScrollOffset = true,
    ScrollPosition? oldPosition,
    String? debugLabel,
    this.negativeScroll = false,
  }) : super(
          physics: physics,
          context: context,
          initialPixels: initialPixels,
          keepScrollOffset: keepScrollOffset,
          oldPosition: oldPosition,
          debugLabel: debugLabel,
        );

  final bool negativeScroll;

  void _forceNegativePixels(double value) {
    super.forcePixels(-value);
  }

  @override
  void saveScrollOffset() {
    if (!negativeScroll) {
      super.saveScrollOffset();
    }
  }

  @override
  void restoreScrollOffset() {
    if (!negativeScroll) {
      super.restoreScrollOffset();
    }
  }

  @override
  double get minScrollExtent => double.negativeInfinity;

  @override
  double get maxScrollExtent => double.infinity;
}
